package com.bocloud.cmp.service.resource;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.dao.CloudServerDao;
import com.bocloud.cmp.dao.CloudVendorDao;
import com.bocloud.cmp.dao.DataStoreDao;
import com.bocloud.cmp.dao.HostSystemDao;
import com.bocloud.cmp.dao.NetworkCardDao;
import com.bocloud.cmp.dao.NetworkDao;
import com.bocloud.cmp.dao.NetworkHostDao;
import com.bocloud.cmp.dao.PortGroupDao;
import com.bocloud.cmp.dao.RegionDao;
import com.bocloud.cmp.dao.SnapshotDao;
import com.bocloud.cmp.dao.StoreHostDao;
import com.bocloud.cmp.dao.VolumeDao;
import com.bocloud.cmp.driver.providers.intf.SnapshotProvider;
import com.bocloud.cmp.driver.providers.intf.VolumeProvider;
import com.bocloud.cmp.entity.resource.CloudServer;
import com.bocloud.cmp.entity.resource.CloudVendor;
import com.bocloud.cmp.entity.resource.DataStore;
import com.bocloud.cmp.entity.resource.HostSystem;
import com.bocloud.cmp.entity.resource.Network;
import com.bocloud.cmp.entity.resource.PortGroup;
import com.bocloud.cmp.entity.resource.Region;
import com.bocloud.cmp.entity.resource.Snapshot;
import com.bocloud.cmp.entity.resource.Volume;
import com.bocloud.cmp.enums.VMStatus;
import com.bocloud.cmp.enums.VendorType;
import com.bocloud.cmp.interfaces.resource.SnapshotService;
import com.bocloud.cmp.model.SnapshotBean;
import com.bocloud.cmp.model.SnapshotModel;
import com.bocloud.cmp.service.model.OperateResult;
import com.bocloud.cmp.service.utils.ResourceEventPublisher;
import com.bocloud.cmp.service.utils.SyncVmwareUtils;
import com.bocloud.common.model.BsmResult;
import com.bocloud.common.model.GridBean;
import com.bocloud.common.model.Param;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.JSONTools;
import com.bocloud.common.utils.MapTools;
import com.bocloud.coordinator.harmony.HarmonyLock;
import com.bocloud.coordinator.harmony.LockFactory;
import com.google.common.collect.Maps;

/**
 * 快照Service接口实现
 * 
 * @author dongkai
 *
 */
@Service("snapshotService")
public class SnapshotServiceImpl implements SnapshotService {

    private static Logger logger = LoggerFactory.getLogger(SnapshotServiceImpl.class);
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private SnapshotDao snapshotDao;
    @Autowired
    private CloudVendorDao cloudVendorDao;
    @Autowired
    private CloudServerDao cloudServerDao;
    @Autowired
    private HostSystemDao hostSystemDao;
    @Autowired
    private NetworkCardDao networkCardDao;
    @Autowired
    private NetworkDao networkDao;
    @Autowired
    private DataStoreDao dataStoreDao;
    @Autowired
    private StoreHostDao storeHostDao;
    @Autowired
    private PortGroupDao portGroupDao;
    @Autowired
    private NetworkHostDao networkHostDao;
    @Autowired
    private VolumeDao volumeDao;
    @Autowired
    private RegionDao regionDao;
    @Autowired
    private SnapshotProvider snapshotProvider;
    @Autowired
    private VolumeProvider volumeProvider;
    @Autowired
    private ResourceEventPublisher resourceEventPublisher;

    @Override
    public BsmResult list(int page, int rows, List<Param> params, Map<String, String> sorter, Boolean simple) {
        try {
            if (null == sorter) {
                sorter = Maps.newHashMap();
            }
            sorter.put("gmtCreate", Common.ONE);
            List<Snapshot> list = snapshotDao.list(page, rows, params, sorter);
            int total = snapshotDao.count(params);
            for (Snapshot snapshot : list) {
                Region region = regionDao.query(snapshot.getRegion());
                CloudVendor cloudVendor = cloudVendorDao.query(snapshot.getVendorId());
                if (null != cloudVendor) {
                    if (VendorType.OPENSTACK.name().equals(cloudVendor.getType())) {
                        snapshot.setVendorName(cloudVendor.getName());
                    } else {
                        if (null != region) {
                            snapshot.setVendorName(cloudVendor.getName());
                            snapshot.setRegionName(region.getName());
                        }
                    }
                }
            }
            GridBean gridBean = GridHelper.getBean(page, rows, total, list);
            return new BsmResult(true, gridBean, "查询成功");
        } catch (Exception e) {
            logger.error("list snapshot failure:", e);
            return new BsmResult(false, "查询失败", null, null);
        }
    }

    @Override
    public BsmResult create(String params, Long userId) {
        JSONObject object = JSONTools.isJSONObj(params);
        Long id = object.getLong(Common.ID);
        Long region = object.getLong(Common.REGION);
        String name = object.getString(Common.NAME);
        Long volumeId = object.getLong("volumeId");
        String remark = object.getString("remark");
        BsmResult result = null;
        try {
            CloudVendor cloudVendor = cloudVendorDao.query(id);
            Volume volume = volumeDao.query(volumeId);
            Region reg = regionDao.query(region);

            if (null == cloudVendor || null == volume) {
                logger.error("get cloudVendor or volume failure!");
                return new BsmResult(false, "创建失败！");
            }
            if (!VendorType.OPENSTACK.name().equals(cloudVendor.getType())) {
                if (null == reg) {
                    logger.error("get region failure!");
                    return new BsmResult(false, "创建失败！");
                }
            }
            SnapshotModel snapshotModel = new SnapshotModel(name, remark, volume.getVolumeId(), volume.getInstanceId());
            BsmResult bsmResult = volumeProvider.snapshot(snapshotModel, cloudVendor.getUuid(), "");
            if (null == bsmResult || !bsmResult.isSuccess()) {
                return new BsmResult(false, "创建快照失败");
            }
            Snapshot snapshot = JSONObject.parseObject(JSONObject.toJSONString(bsmResult.getData()), Snapshot.class);
            String status = snapshot.getStatus();
            snapshot.setVendorId(id);
            snapshot.setStatus(VMStatus.BUILDING.name());
            snapshot.setRegion(region);
            snapshot.setCreaterId(userId);
            snapshotDao.save(snapshot);
            result = new BsmResult(true, "创建任务已下发，正在执行...");
            String snapshotId = snapshot.getSnapshotId();
            // 开启一个线程更新状态
            new Thread(new Runnable() {
                @Override
                public void run() {
                    boolean running = true;
                    String operate = cloudVendor.getType().toLowerCase() + ".snapshot";
                    while (running) {
                        Date start = new Date();
                        SnapshotModel model = new SnapshotModel();
                        model.setSnapshotId(snapshotId);
                        BsmResult bsmResult = snapshotProvider.detail(cloudVendor.getUuid(), null, model);
                        Date end = new Date();
                        if (end.getTime() - start.getTime() > 1000 * 60 * 5) {
                            running = false;
                        }
                        if (bsmResult.isSuccess()) {
                            SnapshotBean bean = JSONObject.parseObject(JSONObject.toJSONString(bsmResult.getData()),
                                    SnapshotBean.class);
                            if (!snapshotId.equals(bean.getSnapshotId())) {
                                continue;
                            }
                            if (bean.getStatus().equals(status)) {
                                try {
                                    Thread.sleep(3000);
                                } catch (Exception e) {
                                    logger.error("thread sleep failure:", e);
                                }
                                continue;
                            }
                            snapshot.setStatus(bean.getStatus());
                            try {
                                snapshotDao.update(snapshot);
                                running = false;
                                resourceEventPublisher
                                        .send(new OperateResult(bsmResult.isSuccess(), "新增快照成功!", operate));
                            } catch (Exception e) {
                                logger.error("update status failure:", e);
                                resourceEventPublisher.send(new OperateResult(false, "新增快照失败!", operate));
                            }
                        }
                    }
                }
            }).start();
            return result;
        } catch (Exception e) {
            logger.error("get cloudvendor and reg error:", e);
            return new BsmResult(false, "创建失败!");
        }
    }

    @Override
    public BsmResult remove(Long id, Long userId) {
        String path = Snapshot.class.getSimpleName() + "_" + id;
        HarmonyLock lock = null;
        try {
            lock = lockFactory.getLock(path);
            if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
                logger.warn("Get harmonyLock time out!");
                return new BsmResult(false, "请求超时", "", "");
            }
            Snapshot snap = snapshotDao.query(id);
            if (null == snap) {
                logger.warn("snapshot data not exist");
                return new BsmResult(false, "数据不存在", "", "");
            }
            // 云供应商
            CloudVendor vendor = cloudVendorDao.query(snap.getVendorId());
            if (null == vendor) {
                return new BsmResult(false, "获取云供应商失败");
            }
            VendorType type = VendorType.valueOf(vendor.getType());
            switch (type) {
            case VMWARE:
                CloudServer server = cloudServerDao.query(snap.getVmId());
                if (null == server) {
                    logger.warn("CloudServer data not exist");
                    return new BsmResult(false, "虚拟机不存在");
                }
                HostSystem host = hostSystemDao.query(server.getHostId());
                if (null == host) {
                    logger.warn("HostSystem data not exist");
                    return new BsmResult(false, "宿主机不存在");
                }
                if (host.isMaintain()) {
                    return new BsmResult(false, "该快照的虚拟机所在宿主机处于维护模式下，无法执行删除快照任务");
                }
                break;
            default:
                break;
            }
            // 启动一个线程从MQ上获取数据
            new Thread(new Runnable() {
                @Override
                public void run() {
                    String operate = vendor.getType().toLowerCase() + ".snapshot";
                    try {
                        SnapshotModel model = new SnapshotModel();
                        model.setSnapshotId(snap.getSnapshotId());
                        BsmResult result = null;
                        switch (type) {
                        case OPENSTACK:
                            result = snapshotProvider.remove(vendor.getUuid(), null, model);
                            break;
                        case VMWARE:
                            Long vmId = snap.getVmId();
                            CloudServer server = cloudServerDao.query(vmId);
                            if (null != server) {
                                model.setVmName(server.getName());
                                model.setInstanceId(server.getInstanceId());
                                result = snapshotProvider.remove(vendor.getUuid(), null, model);
                            }
                            break;
                        default:
                            break;
                        }
                        if (null != result && result.isSuccess()) {
                            snapshotDao.remove(id, userId);
                            resourceEventPublisher.send(new OperateResult(result.isSuccess(), result.getMessage(),
                                    operate, MapTools.simpleMap("vendorId", vendor.getId())));
                        } else {
                            resourceEventPublisher.send(new OperateResult(false, "删除快照失败", operate,
                                    MapTools.simpleMap("vendorId", vendor.getId())));
                        }
                    } catch (Exception e) {
                        logger.error("Get Message Exception:", e);
                        resourceEventPublisher.send(new OperateResult(false, "删除快照失败", operate,
                                MapTools.simpleMap("vendorId", vendor.getId())));
                    }
                }
            }).start();
            return new BsmResult(true, "删除任务已经下发，正在执行……");
        } catch (Exception e) {
            logger.error("remove snapshot fail:", e);
            return new BsmResult(false, "删除失败", "", "");
        } finally {
            if (null != lock) {
                lock.release();
            }
        }
    }

    @Override
    public BsmResult detail(Long id) {
        try {
            Snapshot snapshot = snapshotDao.query(id);
            Region region = regionDao.query(snapshot.getRegion());
            CloudVendor cloudVendor = cloudVendorDao.query(snapshot.getVendorId());
            if (null != cloudVendor) {
                if (VendorType.OPENSTACK.name().equals(cloudVendor.getType())) {
                    snapshot.setVendorName(cloudVendor.getName());
                } else {
                    if (null != region) {
                        snapshot.setVendorName(cloudVendor.getName());
                        snapshot.setRegionName(region.getName());
                    }
                }
            }
            return new BsmResult(true, snapshot, "查询详情成功");
        } catch (Exception e) {
            logger.error("query volume detail fail:", e);
            return new BsmResult(false, "查询详情失败", "", "");
        }
    }

    @Override
    public BsmResult revert(Long id, Long userId) {
        String path = Snapshot.class.getSimpleName() + "_" + id;
        HarmonyLock lock = null;
        try {
            lock = lockFactory.getLock(path);
            if (!lock.acquire(path, 10, TimeUnit.SECONDS)) {
                logger.warn("Get harmonyLock time out!");
                return new BsmResult(false, "请求超时", "", "");
            }
            Snapshot snap = snapshotDao.query(id);
            if (null == snap) {
                logger.warn("snapshot data not exist");
                return new BsmResult(false, "数据不存在", "", "");
            }
            // 云供应商
            CloudVendor vendor = cloudVendorDao.query(snap.getVendorId());
            if (null == vendor) {
                return new BsmResult(false, "获取云供应商失败");
            }
            VendorType type = VendorType.valueOf(vendor.getType());
            switch (type) {
            case VMWARE:
                CloudServer server = cloudServerDao.query(snap.getVmId());
                if (null == server) {
                    logger.warn("CloudServer data not exist");
                    return new BsmResult(false, "虚拟机不存在");
                }
                HostSystem host = hostSystemDao.query(server.getHostId());
                if (null == host) {
                    logger.warn("HostSystem data not exist");
                    return new BsmResult(false, "宿主机不存在");
                }
                if (host.isMaintain()) {
                    return new BsmResult(false, "该快照的虚拟机所在宿主机处于维护模式下，无法执行恢复当前快照任务");
                }
                break;
            default:
                break;
            }
            // 启动一个线程从MQ上获取数据
            new Thread(new Runnable() {
                @Override
                public void run() {
                    String operate = vendor.getType().toLowerCase() + ".snapshot";
                    try {
                        SnapshotModel model = new SnapshotModel();
                        model.setSnapshotId(snap.getSnapshotId());
                        BsmResult result = null;
                        switch (type) {
                        case OPENSTACK:
                            result = snapshotProvider.revert(vendor.getUuid(), null, model);
                            break;
                        case VMWARE:
                            Long vmId = snap.getVmId();
                            CloudServer server = cloudServerDao.query(vmId);
                            if (null != server) {
                                model.setVmName(server.getName());
                                model.setInstanceId(server.getInstanceId());
                                HostSystem host = hostSystemDao.query(server.getHostId());
                                if (null != host) {
                                    model.setHostName(host.getName());
                                }
                                result = snapshotProvider.revert(vendor.getUuid(), null, model);
                                if (result.isSuccess()) {
                                    String content = JSONObject.toJSONString(result.getData());
                                    CloudServer cloudServer = JSONObject.parseObject(content, CloudServer.class);
                                    // 数据中心的存储信息
                                    Map<String, Long> storeMap = new HashMap<>();
                                    List<DataStore> stores = dataStoreDao.listByVdc(host.getVdcId());
                                    // 数据中心的网络信息
                                    Map<String, Long> networkMap = Maps.newHashMap();
                                    Map<String, PortGroup> groupMap = Maps.newHashMap();
                                    List<Network> oldNetworks = networkDao.listByVdc(host.getVdcId());
                                    for (Network network : oldNetworks) {
                                        networkMap.put(network.getNetworkVal(), network.getId());
                                        List<PortGroup> groups = portGroupDao.listByNetwork(network.getId());
                                        for (PortGroup group : groups) {
                                            groupMap.put(group.getGroupVal(), group);
                                        }
                                    }
                                    for (DataStore store : stores) {
                                        storeMap.put(store.getStoreVal(), store.getId());
                                    }
                                    SyncVmwareUtils utils = new SyncVmwareUtils(cloudServerDao, dataStoreDao,
                                            hostSystemDao, snapshotDao, networkDao, null, storeHostDao, networkCardDao,
                                            portGroupDao, networkHostDao);
                                    utils.mergeServer(server, cloudServer, host.getPowerState(), vendor.getId(),
                                            host.getId(), userId, storeMap, networkMap, groupMap);
                                }
                            }
                            break;
                        default:
                            break;
                        }
                        if (null != result && result.isSuccess()) {
                            resourceEventPublisher.send(new OperateResult(result.isSuccess(), result.getMessage(),
                                    operate, MapTools.simpleMap("vendorId", vendor.getId())));
                        } else {
                            resourceEventPublisher.send(new OperateResult(false, "恢复当前快照失败", operate,
                                    MapTools.simpleMap("vendorId", vendor.getId())));
                        }
                    } catch (Exception e) {
                        logger.error("Get Message Exception:", e);
                        resourceEventPublisher.send(new OperateResult(false, "恢复当前快照失败", operate,
                                MapTools.simpleMap("vendorId", vendor.getId())));
                    }
                }
            }).start();
            return new BsmResult(true, "恢复当前快照任务已经下发，正在执行……");
        } catch (Exception e) {
            logger.error("remove snapshot fail:", e);
            return new BsmResult(false, "恢复当前快照失败", "", "");
        } finally {
            if (null != lock) {
                lock.release();
            }
        }
    }

}
